﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core;
using COFE.Core.Lister;
using COFE.Core.Profile;
using System.Text.RegularExpressions;
using COFE.Core.Entry;

namespace COFE.Core
{
    public static class IVolumeRegistrarExtension
    {


        public static IVolume RegisterVolume(this IVolumeRegistrar volumeRegistrar, 
            string factoryKey, IDirectoryLister lister, VolumeAccessMode defAccessMode)
        {            
            IVolume vol = volumeRegistrar.ConstructVolume(factoryKey, lister, defAccessMode);
            volumeRegistrar.RegisterVolume(vol);
            return vol;
        }

        public static IVolume RegisterVolume(this IVolumeRegistrar volumeRegistrar, string factoryKey,
            string listerKey, string paramString, VolumeAccessMode defAccessMode)
        {
            IVolume vol = volumeRegistrar.ConstructVolume(factoryKey, listerKey, paramString, defAccessMode);
            volumeRegistrar.RegisterVolume(vol);
            return vol;
        }

        public static IVolume RegisterVolume(this IVolumeRegistrar volumeRegistrar, string factoryKey,
           string listerKey, VolumeAccessMode defAccessMode)
        {
            return volumeRegistrar.RegisterVolume(factoryKey, listerKey, "", defAccessMode);
        }


        public static IEnumerable<IVolume> GetSecondaryVolumes(this IVolumeRegistrar registrar)
        {
            return from v in registrar.Volumes.Values 
                   where v.DirectoryLister is ISecondaryDirectoryLister 
                   select v;

        }

        #region ConvertEntry, AppendEntries
        /// <summary>
        /// Call SecondaryVolumes and ask whether they need to convert an entries to another.
        /// </summary>
        /// <param name="entries"></param>
        /// <returns></returns>
        public static bool ConvertEntry(this IVolumeRegistrar registrar, 
            IPropertyProvider primPropProvider, 
            out IPropertyProvider outputPrimaryProvider, 
            out IVolume outputVolume, EntryConstructionFlags flags)
        {
            foreach (var vol in registrar.GetSecondaryVolumes())
            {
                ISecondaryDirectoryLister secondaryLister = vol.DirectoryLister as ISecondaryDirectoryLister;

                bool isMatch = secondaryLister.ConvertableFileNamePatterns.Length == 0;
                string entryName = primPropProvider.GetProperty(FileSystemInfoProperties.Name).ValueAsString;
                foreach (var pattern in secondaryLister.ConvertableFileNamePatterns)
                    if (Regex.IsMatch(entryName, pattern))
                        isMatch = true;

                if (isMatch)
                {
                    outputVolume = vol;
                    outputPrimaryProvider = 
                        secondaryLister.ConvertEntry(primPropProvider, flags);
                    if (outputPrimaryProvider != null)
                        return true;
                }
            }
            outputVolume = null;
            outputPrimaryProvider = null;
            return false;
        }

        public static IPropertyProvider ConvertEntry(this IVolumeRegistrar registrar,
            IPropertyProvider primPropProvider,
            EntryConstructionFlags flags)
        {
            IPropertyProvider outputPrimaryProvider;
            IVolume outputVolume;
            if (registrar.ConvertEntry(primPropProvider, out outputPrimaryProvider, out outputVolume, flags))
                return outputPrimaryProvider;
            else return primPropProvider;
        }


        /// <summary>
        /// Call SecondaryVolumes and ask whether they want to append entries in the specific directory
        /// </summary>
        /// <param name="parent"></param>
        /// <returns></returns>
        public static IEnumerable<IInternalFileSystemInfoExA> AppendEntries(this IVolumeRegistrar registrar, IInternalDirectoryInfoExA parent)
        {
            foreach (var dlInfos in registrar.GetSecondaryVolumes())
            {
                ISecondaryDirectoryLister secondaryLister = dlInfos.DirectoryLister as ISecondaryDirectoryLister;
                foreach (var entry in secondaryLister.AppendEntries(parent))
                    yield return entry;
            }
        }
        #endregion

        #region Create Entry

        /// <summary>
        /// Call SecondaryDirectoryLister's CreateVirtualDirectory() to construct a file-based directory. 
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="dir"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static IInternalDirectoryInfoExA CreateVirtualDirectory(this IVolumeRegistrar registrar, IInternalDirectoryInfoExA parent, string dirName, string type)
        {
            if (type.StartsWith("."))
                type = type.TrimStart('.');

            if (type == "")
                return parent.CreateDirectory(dirName) as IInternalDirectoryInfoExA;

            foreach (var listerInfo in registrar.GetSecondaryVolumes())
            {
                IInternalDirectoryInfoExA result =
                    (listerInfo.DirectoryLister as ISecondaryDirectoryLister).CreateVirtualDirectory(parent, dirName, type);
                //Create special directory
                if (result != null)
                    return result;
            }
            throw new ArgumentException("Not supported type : " + type);
        }

        #endregion
    }
}
